package api

import (
	"context"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"mxshop-api/forms"
	"mxshop-api/global"
	"mxshop-api/global/response"
	"mxshop-api/middlewares"
	"mxshop-api/models"
	"mxshop-api/proto"
	"net/http"
	"strconv"
	"strings"
	"time"
)

func handleGrpcErrorToHttp(err error, c *gin.Context) {
	//将grpc的code转换成http的状态吗
	if err != nil {
		if e, ok := status.FromError(err); ok {
			switch e.Code() {
			case codes.NotFound:
				c.JSON(http.StatusNotFound, gin.H{
					"msg": e.Message(),
				})
			case codes.Internal:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "内部错误" + e.Message(),
				})
			case codes.InvalidArgument:
				c.JSON(http.StatusBadRequest, gin.H{
					"msg": "参数错误" + e.Message(),
				})
			default:
				c.JSON(http.StatusInternalServerError, gin.H{
					"msg": "其他错误" + e.Message(),
				})
			}
			return
		}
	}
}

func HandleValidatorError(ctx *gin.Context, err error) {
	errs, ok := err.(validator.ValidationErrors)
	if !ok {
		ctx.JSON(http.StatusOK, gin.H{
			"msg": err.Error(),
		})
		return
	}
	ctx.JSON(http.StatusBadRequest, gin.H{
		"error": removeTopStruct(errs.Translate(global.Trans)),
	})
	return
}

// 去除前面结构体名字:"User.id": "id为必填字段"  ==>"name": "name为必填字段",
func removeTopStruct(fields map[string]string) map[string]string {
	resp := map[string]string{}
	for k, v := range fields {
		resp[k[strings.Index(k, ".")+1:]] = v
	}
	return resp
}

func GetUserList(ctx *gin.Context) {
	zap.S().Debug("获取用户列表")
	host := fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port)
	conn, err := grpc.Dial(host, grpc.WithInsecure())
	if err != nil {
		zap.S().Error("连接失败", zap.Error(err))
		ctx.JSON(200, gin.H{
			"message": "连接失败",
			"data":    err.Error(),
		})
		return
	}
	defer conn.Close()
	userClient := proto.NewUserClient(conn)
	pn := ctx.DefaultQuery("page", "1")
	page, _ := strconv.Atoi(pn)
	pSize := ctx.DefaultQuery("pageSize", "10")
	pageSize, _ := strconv.Atoi(pSize)
	result, err := userClient.GetUserList(ctx.Request.Context(), &proto.PageInfo{Page: uint32(page),
		PageSize: uint32(pageSize),
	})
	if err != nil {
		zap.S().Error("获取用户列表失败", zap.Error(err))
		handleGrpcErrorToHttp(err, ctx)
		ctx.JSON(200, gin.H{
			"message": "获取用户列表失败",
			"data":    err.Error(),
		})
		return
	}
	resp := make([]interface{}, 0)
	for _, value := range result.Data {
		user := response.UserResponse{
			Id:   value.Id,
			Name: value.NickName,
			//Birthday: time.Unix(int64(value.BirthDay), 0),
			//Birthday: time.Unix(int64(value.BirthDay), 0).Format("2016-01-01"),
			Birthday: response.JsonTime(time.Unix(int64(value.BirthDay), 0)),

			Mobile: value.Mobile,
			Gender: value.Gender,
		}
		//data := make(map[string]interface{})
		//data["id"] = value.Id
		//data["name"] = value.NickName
		//data["birthday"] = value.BirthDay
		//data["gender"] = value.Gender
		//data["mobile"] = value.Mobile
		resp = append(resp, user)
	}
	ctx.JSON(200, gin.H{
		"message": "获取用户列表成功",
		"data":    resp,
	})
}

func PassWordLogin(ctx *gin.Context) {
	passwordLoginForm := forms.PassWordLoginForm{}
	if err := ctx.ShouldBind(&passwordLoginForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}
	host := fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port)
	conn, err := grpc.Dial(host, grpc.WithInsecure())
	if err != nil {
		zap.S().Error("连接失败", zap.Error(err))
		ctx.JSON(200, gin.H{
			"message": "连接失败",
			"data":    err.Error(),
		})
		return
	}
	defer conn.Close()
	userClient := proto.NewUserClient(conn)
	userInfo, err := userClient.GetUserByMobile(context.Background(), &proto.MobileRequest{
		Mobile: passwordLoginForm.Mobile,
	})
	if err != nil {
		if e, ok := status.FromError(err); ok {
			zap.S().Debug(err)

			switch e.Code() {
			case codes.NotFound:
				ctx.JSON(http.StatusBadRequest, map[string]string{
					"mobile": "用户不存在",
				})
			default:
				ctx.JSON(http.StatusInternalServerError, map[string]string{
					"mobile": "登录失败",
				})
			}
			return
		}
		ctx.JSON(200, gin.H{
			"message": "获取手机号信息失败",
			"data":    err.Error(),
		})
		return
	}
	resp, err := userClient.CheckPassWord(context.Background(), &proto.PasswordCheckInfo{
		PassWord:          passwordLoginForm.PassWord,
		EncryptedPassWord: userInfo.PassWord,
	})
	zap.S().Debug(resp)

	if resp.Success {
		j := middlewares.NewJWT()
		claims := models.CustomClaims{
			ID:          uint(userInfo.Id),
			NickName:    userInfo.NickName,
			AuthorityId: uint(userInfo.Role),
			StandardClaims: jwt.StandardClaims{
				NotBefore: time.Now().Unix(),
				ExpiresAt: time.Now().Unix() + 60*60*24*30,
				Issuer:    "gordon",
			},
		}
		token, err := j.CreateToken(claims)
		if err != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{
				"msg": "生成token失败",
			})
			return
		}
		ctx.JSON(http.StatusOK, gin.H{
			"message":   "密码验证成功",
			"data":      resp.Success,
			"token":     token,
			"expireAt0": (time.Now().Unix() + 60*60*24*30),
		})
	} else {
		ctx.JSON(http.StatusNotFound, gin.H{
			"message": "密码错误",
			"data":    resp.Success,
		})
	}

	return
}
